﻿#pragma once
#include "XyNet/Endpoint/RpcEndpoint.h"
#include "XyNet/Protocol/cpp/Rpc.service.h"

namespace XyNet
{
	class RpcChannel;

	/// rpc客户端，允许多查询，格式如"192.168.1.1:8000; www.google.com:80"
	class XYNET_API RpcClient : public RpcEndpoint
	{
	public:
		/// rpc客户端配置
		class XYNET_API Config : public RpcEndpoint::Config
		{
		public:
			explicit Config(const string& baseFileName = "");

			/// 查询
			XYNET_CONFIG_PROPERTY(Queries, string, "localhost:12345");
			/// 最多尝试次数
			XYNET_CONFIG_CHECK_PROPERTY(MaxNumberOfTries, int, 3, value > 0);
			/// 尝试时间间隔（秒）
			XYNET_CONFIG_CHECK_PROPERTY(TryInterval, int, 3, value > 0);
			/// 心跳时间间隔（秒）
			XYNET_CONFIG_CHECK_PROPERTY(HeartBeatInterval, int, 25, value > 0);
		};

		//////////////////////////////////////////////////////////////////////////

	public:
		/// 服务端断开处理器
		typedef function<void(shared_ptr<const RpcError>)> ServerErrorHandler;

	public:
		explicit RpcClient(shared_ptr<Config> config);
		~RpcClient();

		/// 获取配置
		shared_ptr<const Config> getConfig() const;
		/// 获取套接字通道
		shared_ptr<RpcChannel> getChannel();

		/// 获取用户数据
		template <typename Type>
		Type getUserData() const
		{
			return _socketChannel->getUserData<Type>();
		}

		/// 是否连接完成
		bool isConnectComplete();
		/// 开始连接
		void startConnect();
		/// 断开连接
		void disconnect();

		/// 设置服务端错误处理器
		void setServerErrorHandler(const ServerErrorHandler& handler);
		/// 处理服务端错误
		void handleServerError(shared_ptr<const RpcError> error);

	private:
		/// 处理重连
		void onReconnect(const boost::system::error_code& error);
		/// 处理连接
		void handleConnect(const boost::system::error_code& error);

		/// 设置并解析查询列表
		void setQueries(const string& queries);

		/// 创建广播通道
		virtual shared_ptr<RpcBroadcastChannel> createBroadcastChannel() override;
		/// 查找套接字通道
		virtual shared_ptr<RpcSocketChannel> findSocketChannel(const Id& id) const override;
		/// 处理套接字通道异常
		virtual void handleSocketChannelException(
			shared_ptr<RpcSocketChannel> socketChannel, int errorCode) override;

		/// 开始心跳计时器
		void startHeartBeatTimer();

		/// 处理心跳
		static void handleHeartBeat(weak_ptr<RpcSocketChannel> weakSocketChannel,
			const boost::system::error_code& error);

	private:
		/// 连接解析器
		shared_ptr<boost::asio::ip::tcp::resolver> _resolver;
		/// 地址查询列表
		vector<boost::asio::ip::tcp::resolver::query> _queries;

		/// 套接字通道
		shared_ptr<RpcSocketChannel> _socketChannel;
		/// 是否正在连接
		bool _connecting;
		/// 重试次数
		int _numberOfTries;
		/// 重试计时器
		shared_ptr<boost::asio::deadline_timer> _reconnectTimer;

		/// 心跳计时器
		unique_ptr<boost::asio::deadline_timer> _heartBeatTimer;

		/// 服务端错误处理器
		ServerErrorHandler _serverErrorHandler;
	};

	//////////////////////////////////////////////////////////////////////////

	class XYNET_API ClientBaseServiceImpl : public BaseService
	{
	public:
		ClientBaseServiceImpl(RpcClient* client);

		virtual void onSendError(SendErrorMethod::Argument* argument) override;

		virtual void onSendHeartBeat(SendHeartBeatMethod::Argument* argument) override;

		virtual void onGetUtcTime(GetUtcTimeMethod::Argument* argument) override;

		virtual void onGetBrokerQueries(GetBrokerQueriesMethod::Argument* argument) override;

	private:
		RpcClient* _client;
	};
}

//////////////////////////////////////////////////////////////////////////

namespace XyNet
{
	extern "C"
	{
		/// 创建RpcClient对象
		XYNET_API RpcClient* RpcClientCreate(string* queries, bool crypto);
		/// 销毁RpcClient对象
		XYNET_API void RpcClientDestroy(RpcClient* client);
		/// RpcClient获取通道
		XYNET_API RpcChannel* RpcClientGetSocketChannel(RpcClient* client);
		/// RpcClient获取通道
		XYNET_API bool RpcClientIsConnectComplete(RpcClient* client);
		/// RpcClient获取通道
		XYNET_API void RpcClientStartConnect(RpcClient* client);
	}
}